Add bare-bones cross compilation support to cargo
authorAlex Crichton <alex@alexcrichton.com>
Thu, 10 Jul 2014 23:03:01 +0000 (16:03 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Thu, 10 Jul 2014 23:03:01 +0000 (16:03 -0700)
This adds a new flag, --target, to the `cargo-build` command. This flag will
indicate that all output should be scoped under the `$triple` directory inside
of the output `target` directory. The compiler is invoked with `--target
$triple` and all custom build commands are passed `TRIPLE` if one is provided.

src/bin/cargo-build.rs
src/bin/cargo-git-checkout.rs
src/bin/cargo-test.rs
src/cargo/ops/cargo_compile.rs
src/cargo/ops/cargo_rustc.rs
src/cargo/util/config.rs

index d0530615c4eb0d204e70f88d243b2711ecc78a80..9e4ef547e8804e818d9db16de617d4a214203616 100644 (file)
@@ -24,6 +24,7 @@ pub struct Options {
     manifest_path: Option<String>,
     update_remotes: bool,
     jobs: Option<uint>,
+    target: Option<String>,
     release: bool,
 }
 
@@ -59,7 +60,8 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
         update: options.update_remotes,
         env: env,
         shell: shell,
-        jobs: options.jobs
+        jobs: options.jobs,
+        target: options.target.as_ref().map(|t| t.as_slice()),
     };
 
     ops::compile(&root, opts).map(|_| None).map_err(|err| {
index d0d4a920c73a049ec40f1a9a7904b799dcdbc797..3e1d601f771f0a1fb7776edad172533260fb8bfa 100644 (file)
@@ -37,7 +37,7 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
 
     let source_id = SourceId::for_git(&url, reference.as_slice());
 
-    let mut config = try!(Config::new(shell, true, None).map_err(|e| {
+    let mut config = try!(Config::new(shell, true, None, None).map_err(|e| {
         CliError::from_boxed(e, 1)
     }));
     let mut source = GitSource::new(&source_id, &mut config);
index 1967c59fdf298c1e132b4d54f7fa87623aee2f4b..b0e2a41a4e54598a7203af616c5dbb55f75402a0 100644 (file)
@@ -49,7 +49,8 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
         update: options.update,
         env: "test",
         shell: shell,
-        jobs: options.jobs
+        jobs: options.jobs,
+        target: None,
     };
 
     try!(ops::compile(&root, compile_opts).map(|_| None::<()>).map_err(|err| {
index 340ff4c26db73f6375f65e70d92d9d5fc5a17568..427616b9da70984e24bb36127482610d8d1806c4 100644 (file)
@@ -34,11 +34,13 @@ pub struct CompileOptions<'a> {
     pub update: bool,
     pub env: &'a str,
     pub shell: &'a mut MultiShell,
-    pub jobs: Option<uint>
+    pub jobs: Option<uint>,
+    pub target: Option<&'a str>,
 }
 
 pub fn compile(manifest_path: &Path, options: CompileOptions) -> CargoResult<()> {
-    let CompileOptions { update, env, shell, jobs } = options;
+    let CompileOptions { update, env, shell, jobs, target } = options;
+    let target = target.map(|s| s.to_string());
 
     log!(4, "compile; manifest-path={}", manifest_path.display());
 
@@ -58,7 +60,7 @@ pub fn compile(manifest_path: &Path, options: CompileOptions) -> CargoResult<()>
     let source_ids = package.get_source_ids();
 
     let (packages, resolve) = {
-        let mut config = try!(Config::new(shell, update, jobs));
+        let mut config = try!(Config::new(shell, update, jobs, target.clone()));
 
         let mut registry =
             try!(PackageRegistry::new(source_ids, override_ids, &mut config));
@@ -81,7 +83,7 @@ pub fn compile(manifest_path: &Path, options: CompileOptions) -> CargoResult<()>
         target.get_profile().get_env() == env
     }).collect::<Vec<&Target>>();
 
-    let mut config = try!(Config::new(shell, update, jobs));
+    let mut config = try!(Config::new(shell, update, jobs, target));
 
     try!(ops::compile_targets(env.as_slice(), targets.as_slice(), &package,
          &PackageSet::new(packages.as_slice()), &resolve, &mut config));
index d8be4f11ab3bdbe860e91e131f4ca211846e232d..378efd9027a39e9bf8cc3cb44be952125eaa43bb 100644 (file)
@@ -54,8 +54,9 @@ pub fn compile_targets<'a>(env: &str, targets: &[&Target], pkg: &Package,
 
     debug!("compile_targets; targets={}; pkg={}; deps={}", targets, pkg, deps);
 
-    let path_fragment = uniq_target_dest(targets);
-    let target_dir = pkg.get_absolute_target_dir().join(path_fragment.unwrap_or(""));
+    let target_dir = pkg.get_absolute_target_dir()
+                        .join(config.target().unwrap_or(""))
+                        .join(uniq_target_dest(targets).unwrap_or(""));
     let deps_target_dir = target_dir.join("deps");
 
     let output = try!(util::process("rustc").arg("-v").exec_with_output());
@@ -223,7 +224,8 @@ fn compile_custom(pkg: &Package, cmd: &str,
                      .cwd(pkg.get_root())
                      .env("OUT_DIR", Some(cx.dest.as_str().expect("non-UTF8 dest path")))
                      .env("DEPS_DIR", Some(cx.dest.join(cx.deps_dir)
-                                             .as_str().expect("non-UTF8 deps path")));
+                                             .as_str().expect("non-UTF8 deps path")))
+                     .env("TARGET", cx.config.target());
     for arg in cmd {
         p = p.arg(arg);
     }
@@ -326,6 +328,14 @@ fn build_base_args(into: &mut Args,
         into.push("-o".to_string());
         into.push(out.join(target.get_name()).display().to_string());
     }
+
+    match cx.config.target() {
+        Some(target) => {
+            into.push("--target".to_string());
+            into.push(target.to_string());
+        }
+        None => {}
+    }
 }
 
 fn build_deps_args(dst: &mut Args, package: &Package, cx: &Context) {
index de48b375d9e321b76942ef604a278aebcf15e049..1745ae1ce78041a2105647c43521321c37a4c592 100644 (file)
@@ -12,12 +12,14 @@ pub struct Config<'a> {
     update_remotes: bool,
     shell: &'a mut MultiShell,
     jobs: uint,
+    target: Option<String>,
 }
 
 impl<'a> Config<'a> {
     pub fn new<'a>(shell: &'a mut MultiShell,
                    update_remotes: bool,
-                   jobs: Option<uint>) -> CargoResult<Config<'a>> {
+                   jobs: Option<uint>,
+                   target: Option<String>) -> CargoResult<Config<'a>> {
         if jobs == Some(0) {
             return Err(human("jobs must be at least 1"))
         }
@@ -29,6 +31,7 @@ impl<'a> Config<'a> {
             update_remotes: update_remotes,
             shell: shell,
             jobs: jobs.unwrap_or(os::num_cpus()),
+            target: target,
         })
     }
 
@@ -48,9 +51,13 @@ impl<'a> Config<'a> {
         self.update_remotes
     }
 
-    pub fn jobs(&mut self) -> uint {
+    pub fn jobs(&self) -> uint {
         self.jobs
     }
+
+    pub fn target<'a>(&'a self) -> Option<&'a str> {
+        self.target.as_ref().map(|t| t.as_slice())
+    }
 }
 
 #[deriving(Eq,PartialEq,Clone,Encodable,Decodable)]